/*
 * @Copyright: 2005-2017 www.2345.com. All rights reserved.
 */
package demo.aspect;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

import demo.util.DateTimeUtils;

/**
 * MongoTemplate切面 1、在日志中打印出mongoTemplate中每个入口方法的入参大小、返回值大小、执行耗时
 *
 */
@Aspect
public class MongoTemplateTraceAspect {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(* org.springframework.data.mongodb.core.MongoTemplate.*(..))")
    public void mongoTemplatePoint() {
        // 方法体留空
    }

    @Around(value = "mongoTemplatePoint()")
    public Object traceAspect(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object result = null;
        Object[] args = null;
        try {
            args = pjp.getArgs();
            result = pjp.proceed(args);
            return result;
        } finally {
            long cost = System.currentTimeMillis() - begin;
            Signature signature = pjp.getSignature();
            int inSize = getSize(args);
            int outSize = getSize(new Object[] { result });
            logger.info("method:{}, begin:{}, in:{} bytes,out:{}bytes ,cost:{}ms", signature.getName(),
                    DateTimeUtils.toLocalDateTime(begin), inSize, outSize, cost);
        }
    }

    private int getSize(Object[] objects) {
        int size = 0;
        if (objects != null && objects.length > 0) {
            try {
                for (Object obj : objects) {
                    if (obj == null) {
                        continue;
                    }
                    int length = JSON.toJSONBytes(obj).length;
                    size += length;
                }
            } catch (Exception e) {
                return -1;
            }
        }
        return size;
    }

}
